/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2020-2022. All rights reserved.
 * Description: Header File, vram common
 * Create: 2023/7/19
 */
#include <linux/kallsyms.h>
#include <linux/errno.h>
#include <linux/version.h>

#include "ossl_knl.h"
#include "vram_common.h"

#ifndef __UEFI__

static int g_use_vram = 0;
static int g_in_kexec = 0;

static register_nvwa_notifier_t _register_nvwa_notifier = NULL;
static unregister_nvwa_notifier_t _unregister_nvwa_notifier = NULL;
static register_euleros_reboot_notifier_t _register_euleros_reboot_notifier = NULL;
static unregister_euleros_reboot_notifier_t _unregister_euleros_reboot_notifier = NULL;
static vram_kalloc_t _vram_kalloc = NULL;
static vram_kfree_t _vram_kfree = NULL;
static vram_get_gfp_vram _vram_get_gfp_vram = NULL;

int hi_register_nvwa_notifier(int hook, struct notifier_block *nb)
{
    if (_register_nvwa_notifier) {
        return _register_nvwa_notifier(hook, nb);
    }

    return -EINVAL;
}
EXPORT_SYMBOL(hi_register_nvwa_notifier);

int hi_unregister_nvwa_notifier(int hook, struct notifier_block *nb)
{
    if (_unregister_nvwa_notifier) {
        return _unregister_nvwa_notifier(hook, nb);
    }

    return -EINVAL;
}
EXPORT_SYMBOL(hi_unregister_nvwa_notifier);

int hi_register_euleros_reboot_notifier(struct notifier_block *nb)
{
    if (_register_euleros_reboot_notifier)
        return _register_euleros_reboot_notifier(nb);

    return -EINVAL;
}
EXPORT_SYMBOL(hi_register_euleros_reboot_notifier);

int hi_unregister_euleros_reboot_notifier(struct notifier_block *nb)
{
    if (_unregister_euleros_reboot_notifier)
        return _unregister_euleros_reboot_notifier(nb);

    return -EINVAL;
}
EXPORT_SYMBOL(hi_unregister_euleros_reboot_notifier);

void __iomem *hi_vram_kalloc(char *name, u64 size)
{
    if (_vram_kalloc) {
        return _vram_kalloc(name, size);
    }

    return NULL;
}
EXPORT_SYMBOL(hi_vram_kalloc);

void hi_vram_kfree(void __iomem *vaddr, char *name, u64 size)
{
    if (_vram_kfree && vaddr) {
        _vram_kfree(vaddr, name, size);
    }

    return;
}
EXPORT_SYMBOL(hi_vram_kfree);

gfp_t hi_vram_get_gfp_vram(void)
{
    if (_vram_get_gfp_vram) {
        return _vram_get_gfp_vram();
    }
    return 0;
}
EXPORT_SYMBOL(hi_vram_get_gfp_vram);

void lookup_vram_related_symbols(void)
{
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)
    _register_nvwa_notifier = (register_nvwa_notifier_t)
        kallsyms_lookup_name("register_nvwa_notifier");

    _unregister_nvwa_notifier = (unregister_nvwa_notifier_t)
        kallsyms_lookup_name("unregister_nvwa_notifier");

    _register_euleros_reboot_notifier = (register_euleros_reboot_notifier_t)
        kallsyms_lookup_name("register_euleros_reboot_notifier");

    _unregister_euleros_reboot_notifier = (unregister_euleros_reboot_notifier_t)
        kallsyms_lookup_name("unregister_euleros_reboot_notifier");

    _vram_kalloc = (vram_kalloc_t)
        kallsyms_lookup_name("vram_kalloc");

    _vram_kfree = (vram_kfree_t)
        kallsyms_lookup_name("vram_kfree");

    _vram_get_gfp_vram = (vram_get_gfp_vram)
        kallsyms_lookup_name("vram_get_vram_gfp_t");
#else
// openEuler: the symbol table cannot be scanned in kernel versions later than 5.10.
#if (!defined(HIUDK_OPENEULER))
    _register_nvwa_notifier = (register_nvwa_notifier_t)
        kallsyms_lookup_name_wrap("register_nvwa_notifier");

    _unregister_nvwa_notifier = (unregister_nvwa_notifier_t)
        kallsyms_lookup_name_wrap("unregister_nvwa_notifier");

    _register_euleros_reboot_notifier = (register_euleros_reboot_notifier_t)
        kallsyms_lookup_name_wrap("register_euleros_reboot_notifier");

    _unregister_euleros_reboot_notifier = (unregister_euleros_reboot_notifier_t)
        kallsyms_lookup_name_wrap("unregister_euleros_reboot_notifier");

    _vram_kalloc = (vram_kalloc_t)
        kallsyms_lookup_name_wrap("vram_kalloc");

    _vram_kfree = (vram_kfree_t)
        kallsyms_lookup_name_wrap("vram_kfree");

    _vram_get_gfp_vram = (vram_get_gfp_vram)
        kallsyms_lookup_name_wrap("vram_get_vram_gfp_t");
#endif
#endif
}
EXPORT_SYMBOL(lookup_vram_related_symbols);

int hi_set_kexec_status(int status)
{
    int *kexec_status_addr = NULL;

    kexec_status_addr = hi_vram_kalloc(KEXEC_SIGN, VRAM_BLOCK_SIZE_2M);
    if (!kexec_status_addr) {
        pr_err("set kexec status vram kalloc failed.\n");
        return -ENOMEM;
    }

    *kexec_status_addr = status;
    g_in_kexec = *kexec_status_addr;

    return 0;
}
EXPORT_SYMBOL(hi_set_kexec_status);

int hi_get_kexec_status(void)
{
    int *kexec_status_addr = NULL;

    kexec_status_addr = hi_vram_kalloc(KEXEC_SIGN, VRAM_BLOCK_SIZE_2M);
    if (!kexec_status_addr) {
        pr_err("get kexec status vram kalloc failed.\n");
        return -ENOMEM;
    }

    g_in_kexec = *kexec_status_addr;
    hi_vram_kfree((void *)kexec_status_addr, KEXEC_SIGN, VRAM_BLOCK_SIZE_2M);

    return 0;
}
EXPORT_SYMBOL(hi_get_kexec_status);

int get_use_vram_flag(void)
{
    return g_use_vram;
}
EXPORT_SYMBOL(get_use_vram_flag);

void set_use_vram_flag(bool flag)
{
    g_use_vram = flag;
}
EXPORT_SYMBOL(set_use_vram_flag);

int vram_get_kexec_flag(void)
{
    return g_in_kexec;
}
EXPORT_SYMBOL(vram_get_kexec_flag);

#endif
